package fr.inserm.umr915.vcfannotator.annotators;

import java.util.regex.Pattern;

import fr.inserm.umr915.libjson.ArrayNode;
import fr.inserm.umr915.libjson.ObjectNode;
import fr.inserm.umr915.vcfannotator.AnnotationException;
import fr.inserm.umr915.vcfannotator.Variant;


import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.SecondaryCursor;

public class PolyphenAnnotator
	extends AbstractDelimitedAnnotator
	{
	private SecondaryCursor cursor=null;
	private DatabaseEntry key=new DatabaseEntry();
	private DatabaseEntry pKey=new DatabaseEntry();
	private DatabaseEntry data=new DatabaseEntry();
	private Variant.Binding variantBinding=new Variant.Binding();
	private String build=null;
	
	public PolyphenAnnotator()
		{
		setPattern(Pattern.compile("[\t]"));
		}
	
	public String getBuild() {
		return build;
		}
	
	public void setBuild(String build)
		{
		this.build = build;
		}
	
	private static boolean isBlank(String s)
		{
		return s==null || s.trim().length()==0;
		}
	
	@Override
	public boolean ignore(String line) {
		return line.startsWith("##");
		}
	
	@Override
	public void annotate(String[] tokens) throws AnnotationException
		{
		if(this.cursor==null)
			{
			this.cursor=super.baseDatabase.getVariantDatabase().openCursor(null, null);
			}
		for(int i=0;i< tokens.length;++i) tokens[i]=tokens[i].trim();
		if(getLineIndex()==1)
			{
			if(tokens.length!=11) throw new AnnotationException("Expected 11 columns in the header");
			if(!tokens[0].equals("#o_snp_id")) throw new AnnotationException("Expected column 1 to be [#o_snp_id] but got ["+tokens[1]+"]");
			if(!tokens[1].equals("snp_id")) throw new AnnotationException("Expected column 2 to be [snp_id] but got ["+tokens[2]+"]");
			if(!tokens[2].equals("acc")) throw new AnnotationException("Expected column 3 to be [acc] but got ["+tokens[3]+"]");
			if(!tokens[3].equals("pos")) throw new AnnotationException("Expected column 4 to be [pos] but got ["+tokens[4]+"]");
			if(!tokens[4].equals("aa1")) throw new AnnotationException("Expected column 5 to be [aa1] but got ["+tokens[5]+"]");
			if(!tokens[5].equals("aa2")) throw new AnnotationException("Expected column 6 to be [aa2] but got ["+tokens[6]+"]");
			if(!tokens[6].equals("prediction")) throw new AnnotationException("Expected column 7 to be [prediction] but got ["+tokens[7]+"]");
			if(!tokens[7].equals("pph2_prob")) throw new AnnotationException("Expected column 8 to be [pph2_prob] but got ["+tokens[8]+"]");
			if(!tokens[8].equals("pph2_FPR")) throw new AnnotationException("Expected column 9 to be [pph2_FPR] but got ["+tokens[9]+"]");
			if(!tokens[9].equals("pph2_TPR")) throw new AnnotationException("Expected column 10 to be [pph2_TPR] but got ["+tokens[10]+"]");
			if(!tokens[10].equals("Comments")) throw new AnnotationException("Expected column 11 to be [Comments] but got ["+tokens[11]+"]");
			return;
			}
		
		int n=tokens[0].indexOf(':');
		if(n==-1) throw new AnnotationException("bad name "+tokens[0]);
		String chrom=tokens[0].substring(0,n);
		int n2=tokens[0].indexOf('.',n);
		if(n2==-1) throw new AnnotationException("bad pos "+tokens[0]);
		int n3=tokens[0].indexOf('.',n2+1);
		if(n3==-1) n3=tokens[0].length();
		int pos=Integer.parseInt(tokens[0].substring(n+1, n2));//minus 1
		String variation= tokens[0].substring(n2+1,n3).toUpperCase();
		if(!variation.matches("[ATGC][ATGC]"))  throw new AnnotationException("bad var "+tokens[0]);
		
		
		
		
		
		
		if(!(   tokens[6].equals("benign") ||
				tokens[6].equals("possibly damaging") ||
				tokens[6].equals("prediction") ||
				tokens[6].equals("probably damaging") ||
				tokens[6].equals("unknown")
				))
			{
			throw new AnnotationException("bad prediction:"+tokens[6]);
			}
		String prediction=tokens[6].toUpperCase().replace(' ', '_');

		
		
		Variant var=new Variant(
			getBuild(),
			chrom,
			pos,
			variation.substring(0,1).toUpperCase(),
			variation.substring(1).toUpperCase()
			);
		
		variantBinding.objectToEntry(var, key);
		
		OperationStatus op=cursor.getSearchKey(key,pKey, data, LockMode.DEFAULT);
		if(op!=OperationStatus.SUCCESS) return;
		
		LOG.info("found pph2 "+tokens[0]+" "+var);
		
		
		ObjectNode annotation= nodeBinding.entryToObject(data).asObjectNode();
		ArrayNode array=(ArrayNode)annotation.get("polyphen");
		if(array==null)
			{
			array=super.nodeFactory.createArrayNode();
			annotation.put("polyphen",array);
			}
		
		ObjectNode meta=super.nodeFactory.createObjectNode(11);
		if(!tokens[0].equals(tokens[1]))
			{
			meta.put("snp-id", tokens[1]);
			}
	
		if(!isBlank(tokens[2])) meta.put("acc", tokens[2]);
		if(!isBlank(tokens[3])) meta.put("pos", tokens[3]);
		if(!isBlank(tokens[4])) meta.put("aa1", tokens[4]);
		if(!isBlank(tokens[5])) meta.put("aa2", tokens[5]);
		
		if(!isBlank(tokens[7])) meta.put("pph2_prob",tokens[7]);
		if(!isBlank(tokens[8])) meta.put("pph2_FPR",tokens[8]);
		if(!isBlank(tokens[9])) meta.put("pph2_TPR",tokens[9]);
		if(tokens.length>10 && !isBlank(tokens[10])) meta.put("comment",tokens[10]);
		
		meta.put("prediction", prediction);
		
		if(!array.insert(meta)) return;
		nodeBinding.objectToEntry(annotation, data);
		if(baseDatabase.getJsonDatabase().put(null, pKey, data)!=OperationStatus.SUCCESS)
			{
			throw new RuntimeException("Cannot re-insert "+var+":"+annotation);
			}
			
		}
	
	@Override
	public void cleanup() {
		if(this.cursor!=null)
			{
			this.cursor.close();
			}
		this.cursor=null;
		super.cleanup();
		}
	
	}
